package org.artifact.core.db;

import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.sql.DataSource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.artifact.core.lang.IServer;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
public abstract class MySqlDao<T extends BaseBean<T>> extends BaseDao<T>{
	
	static final Log log = LogFactory.get(MySqlDao.class);
	
	protected QueryRunner queryRunner;
	
	protected DataSource getDataSource(){
		return IServer.me().getContext().getDataSource();
	}

	protected abstract String getSaveSql();
	
	protected abstract String getDeleteSql();
	
	/** 执行数据库存储 */
	protected void finishSaveCache() {
		int l = 0;
		Object[][] params = new Object[cachedUpdates.size()][0];
		for (Entry<Object, T> e : cachedUpdates.entrySet()) {
			params[l] = (Object[]) e.getValue().write();
			l++;
		}
		batchUpdate(getSaveSql(), params);
	}

	/** 执行数据库删除 */
	protected void finishDeleteCache() {
		int l = 0;
		Object[][] params = new Object[cachedDeletes.size()][1];
		for (Entry<Object, T> e : cachedDeletes.entrySet()) {
			params[l][0] = e.getValue().pk();
			l++;
		}
		batchUpdate(getDeleteSql(), params);
	}
	
	
	
	@Override
	public List<T> findAll() {
		return resultList(()->{
			return find("SELECT * FROM " + getTableName());	
		}, t -> true);
		
	}

	@Override
	public T findByPrimaryKey(Object primaryKey) {
		return resultFirst(()->{
			return findFirst(MessageFormat.format("SELECT * FROM {0} WHERE {1} = {2}",getTableName(),getPKFieldName(),primaryKey.toString()));	
		}, t -> ObjectUtil.equal(t.pk(), primaryKey));
	}

	/** 
     * 执行sql语句 
     * @param sql sql语句 
     * @return 受影响的行数 
     */ 
    protected int update(String sql) { 
        return update(sql, null); 
    } 
      
    /** 
     * 执行sql语句 
     * <code> 
     * executeUpdate("update user set username = 'kitty' where username = ?", "hello kitty"); 
     * </code> 
     * @param sql sql语句 
     * @param param 参数 
     * @return 受影响的行数 
     */ 
    protected int update(String sql, Object param) { 
        return update(sql, new Object[] { param }); 
    } 
      
    /** 
     * 执行sql语句 
     * @param sql sql语句 
     * @param params 参数数组 
     * @return 受影响的行数 
     */ 
    protected int update(String sql, Object[] params) { 
        queryRunner = new QueryRunner(getDataSource()); 
        int affectedRows = 0; 
        try { 
            if (params == null) { 
                affectedRows = queryRunner.update(sql); 
            } else { 
                affectedRows = queryRunner.update(sql, params); 
            } 
        } catch (SQLException e) { 
            log.error(e,"Error occured while attempting to update data"); 
        } 
        return affectedRows; 
    } 
      
    /** 
     * 执行批量sql语句 
     * @param sql sql语句 
     * @param params 二维参数数组 
     * @return 受影响的行数的数组 
     */ 
    protected int[] batchUpdate(String sql, Object[][] params) { 
        queryRunner = new QueryRunner(getDataSource()); 
        int[] affectedRows = new int[0]; 
        try { 
            affectedRows = queryRunner.batch(sql, params); 
        } catch (SQLException e) { 
            log.error(e,"Error occured while attempting to batch update data"); 
        } 
        return affectedRows; 
    }     

//    /** 
//     * 执行查询，将每行的结果保存到一个Map对象中，然后将所有Map对象保存到List中 
//     * @param sql sql语句 
//     * @return 查询结果 
//     */ 
//    protected List<Map<String, Object>> find(String sql) { 
//        return find(sql, null); 
//    } 
//      
//    /** 
//     * 执行查询，将每行的结果保存到一个Map对象中，然后将所有Map对象保存到List中 
//     * @param sql sql语句 
//     * @param param 参数 
//     * @return 查询结果 
//     */ 
//    protected List<Map<String, Object>> find(String sql, Object param) { 
//        return find(sql, new Object[] {param}); 
//    } 
//      
//    /** 
//     * 执行查询，将每行的结果保存到一个Map对象中，然后将所有Map对象保存到List中 
//     * @param sql sql语句 
//     * @param params 参数数组 
//     * @return 查询结果 
//     */ 
//    protected List<Map<String, Object>> find(String sql, Object[] params) { 
//        queryRunner = new QueryRunner(getDataSource()); 
//        List<Map<String, Object>> list = new ArrayList<Map<String,Object>>(); 
//        try { 
//            if (params == null) { 
//                list = (List<Map<String, Object>>) queryRunner.query(sql, new MapListHandler()); 
//            } else { 
//                list = (List<Map<String, Object>>) queryRunner.query(sql, new MapListHandler(), params); 
//            } 
//        } catch (SQLException e) { 
//            log.error("Error occured while attempting to query data", e); 
//        } 
//        return list; 
//    } 
      
    /** 
     * 执行查询，将每行的结果保存到Bean中，然后将所有Bean保存到List中 
     * @param entityClass 类名 
     * @param sql sql语句 
     * @return 查询结果 
     */ 
    protected List<T> find(String sql) { 
        return find(sql, null); 
    } 
      
    /** 
     * 执行查询，将每行的结果保存到Bean中，然后将所有Bean保存到List中 
     * @param entityClass 类名 
     * @param sql sql语句 
     * @param param 参数 
     * @return 查询结果 
     */ 
    protected List<T> find(String sql, Object param) { 
        return find(sql, new Object[] { param }); 
    } 
      
    /** 
     * 执行查询，将每行的结果保存到Bean中，然后将所有Bean保存到List中 
     * @param entityClass 类名 
     * @param sql sql语句 
     * @param params 参数数组 
     * @return 查询结果 
     */ 
	protected List<T> find(String sql, Object[] params) { 
        queryRunner = new QueryRunner(getDataSource()); 
        List<Object[]> arrays = new ArrayList<Object[]>(); 
        List<T> list = new ArrayList<T>(); 
        try { 
            if (params == null) { 
            	arrays = queryRunner.query(sql, new ArrayListHandler());
            } else { 
            	arrays = queryRunner.query(sql, new ArrayListHandler(), params); 
            }
            for (Object[] array : arrays) {
            	T t = createEntity();
            	t.read(array);
            	list.add(t);
			}
            arrays.clear();
            arrays = null;
        } catch (SQLException e) { 
            log.error(e,"Error occured while attempting to query data"); 
        } 
        return list; 
    } 
      
    /** 
     * 查询出结果集中的第一条记录，并封装成对象 
     * @param entityClass 类名 
     * @param sql sql语句 
     * @return 对象 
     */ 
    protected T findFirst(String sql) { 
        return findFirst(sql, null); 
    } 
      
    /** 
     * 查询出结果集中的第一条记录，并封装成对象 
     * @param entityClass 类名 
     * @param sql sql语句 
     * @param param 参数 
     * @return 对象 
     */ 
    protected T findFirst(String sql, Object param) { 
        return findFirst(sql, new Object[] { param }); 
    } 
      
    /** 
     * 查询出结果集中的第一条记录，并封装成对象 
     * @param entityClass 类名 
     * @param sql sql语句 
     * @param params 参数数组 
     * @return 对象 
     */ 
    protected T findFirst(String sql, Object[] params) { 
        queryRunner = new QueryRunner(getDataSource()); 
        Object[] array = null;
        T t = null;
        try { 
            if (params == null) { 
            	array = queryRunner.query(sql, new ArrayHandler());
            } else { 
                array = queryRunner.query(sql, new ArrayHandler(), params); 
            } 
            if (ArrayUtil.isNotEmpty(array)) {
            	t = createEntity();
            	t.read(array);
            	array = null;
			}
        } catch (SQLException e) { 
            log.error(e,"Error occured while attempting to query data"); 
        } 
        return t; 
    }

	@Override
	public boolean existsTable() {
		queryRunner = new QueryRunner(getDataSource()); 
		boolean isExist = false;
        String sql = "SHOW TABLES IN "+getDBName()+" WHERE Tables_in_"+getDBName()+" = ?";
        try {
			Map<String, Object> rel  = queryRunner.query(sql,new MapHandler(),getTableName());
			if(rel!=null){
	            isExist = true;
	        }
		} catch (SQLException e) {
			e.printStackTrace();
		}
        return isExist;
	} 
    
    
    
}
